package easyScript.stage;

import basicutil.common.ThreadUtil;
import basicutil.pipeline.DataMessage;
import basicutil.pipeline.DataType;
import basicutil.pipeline.State;
import basicutil.pipeline.core.OutputPort;
import org.example.jnautil.key.KeyBoardManager;
import org.example.jnautil.key.RegisterItem;
import org.example.jnautil.key.RegisteredKey;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.atomic.AtomicBoolean;

public class KeyBindStage {
    private static final KeyBoardManager keyBoardManager = KeyBoardManager.INSTANCE;
    private final String id;
    private final List<OutputPort> outputPorts;
    private final AtomicBoolean running;
    private RegisteredKey registeredKey;
    final String keyId;
    final boolean blockListen;

    private Thread waitingThread;
    private State state;
    private String waitObj;

    public KeyBindStage(String id, String keyId, boolean blockListen) {
        this.id = id;

        this.keyId = keyId;
        this.blockListen = blockListen;
        this.outputPorts = new ArrayList<>();
        outputPorts.add(new OutputPort(id + "-out-0", DataType.STRING));

        this.running = new AtomicBoolean();
        registeredKey = new RegisterItem(keyId, blockListen);

    }

    public void start() {
        if (running.compareAndSet(false, true)) {
            keyBoardManager.unregisterKey(registeredKey);
            BlockingQueue<String> strings = keyBoardManager.registerKey(registeredKey);
            ThreadUtil.runLaterSafely(() -> {

                while (isRunning()) {
                    runOnce(strings);

                }
            });
        }
    }

    void runOnce(BlockingQueue<String> strings) {
        try {
            waitingThread = Thread.currentThread();
            state = State.WAIT_PARAM;
            waitObj = keyId;
            String take = strings.take();
            DataMessage dataMessage = new DataMessage(DataType.STRING, take, id);
            state = State.RUNNING;

            if (!isRunning()) {
                stop();
                return;
            }

            outputPorts.get(0).receiveMessage(dataMessage);
        } catch (InterruptedException e) {
            return;
        } catch (Exception e) {
            e.printStackTrace();
            running.set(false);
            return;
        }

    }

    public void stop() {
        if (running.compareAndSet(true, false)) {

            keyBoardManager.unregisterKey(registeredKey);
            if (waitingThread != null && (state == State.WAIT_PARAM || state == State.WAIT_INTERVAL)) {
                waitingThread.interrupt();
            }
            state = State.STOP;
        }

    }

    public void startOnce() {
    }

    public State getState() {
        return state;
    }

    public boolean isRunning() {
        return running.get();
    }

}
